home *** CD-ROM | disk | FTP | other *** search
/ Windows Game Programming for Dummies (2nd Edition) / WinGamProgFD.iso / pc / DirectX SDK / DXSDK / samples / Multimedia / DirectShow / Players / CutScene / cutscene.cpp next >
Encoding:
C/C++ Source or Header  |  2001-10-08  |  9.4 KB  |  351 lines

  1. //------------------------------------------------------------------------------
  2. // File: CutScene.cpp
  3. //
  4. // Desc: DirectShow sample code - simple interactive movie player.  Plays
  5. //       a movie or game cutscene in fullscreen mode.  Supports simple user
  6. //       input to enable ESC, spacebar, or ENTER to quit.
  7. //
  8. // Copyright (c) 1998-2001 Microsoft Corporation.  All rights reserved.
  9. //------------------------------------------------------------------------------
  10.  
  11.  
  12. #include <dshow.h>
  13. #include <stdio.h>
  14. #include <atlbase.h>
  15.  
  16. #include "cutscene.h"
  17.  
  18. //
  19. // Constants
  20. //
  21. #define KEYBOARD_SAMPLE_FREQ  100  // Sample user input on an interval
  22. #define CUTSCENE_NAME   TEXT("Cutscene Player Sample")
  23.  
  24. //
  25. // Globals
  26. //
  27. static IGraphBuilder  *pGB = NULL;
  28. static IMediaControl  *pMC = NULL;
  29. static IVideoWindow   *pVW = NULL;
  30. static IMediaEvent    *pME = NULL;
  31.  
  32. static HWND g_hwndMain=0;
  33. static BOOL g_bContinue=TRUE, g_bUserInterruptedPlayback=FALSE;
  34.  
  35.  
  36. //
  37. // Function prototypes
  38. //
  39. static HRESULT PlayMedia(LPTSTR lpszMovie, HINSTANCE hInstance);
  40. static HRESULT GetInterfaces(void);
  41. static HRESULT SetFullscreen(void);
  42. static BOOL CreateHiddenWindow( HINSTANCE hInstance, TCHAR *szFile );
  43. static LONG WINAPI WindowProc(HWND, UINT, WPARAM, LPARAM);
  44. static void CloseApp();
  45. static void CleanupInterfaces(void);
  46. static void Msg(TCHAR *szFormat, ...);
  47.  
  48.  
  49. //
  50. // Helper Macros (Jump-If-Failed, Log-If-Failed)
  51. //
  52. #define RELEASE(i) {if (i) i->Release(); i = NULL;}
  53.  
  54. #define JIF(x) if (FAILED(hr=(x))) \
  55.     {Msg(TEXT("FAILED(hr=0x%x) in ") TEXT(#x) TEXT("\n"), hr); goto CLEANUP;}
  56.  
  57. #define LIF(x) if (FAILED(hr=(x))) \
  58.     {Msg(TEXT("FAILED(hr=0x%x) in ") TEXT(#x) TEXT("\n"), hr); return hr;}
  59.  
  60.  
  61.  
  62. HRESULT PlayCutscene(LPTSTR szMovie, HINSTANCE hInstance)
  63. {
  64.     HRESULT hr;
  65.  
  66.     // Create the main hidden window to field keyboard input
  67.     if (!CreateHiddenWindow(hInstance, szMovie))
  68.         return E_FAIL;
  69.  
  70.     // Initialize COM
  71.     if (FAILED(hr = CoInitialize(NULL)))
  72.         return hr;
  73.  
  74.     // Get DirectShow interfaces
  75.     if (FAILED(hr = GetInterfaces()))
  76.     {
  77.         CoUninitialize();
  78.         return hr;
  79.     }
  80.  
  81.     // Play the movie / cutscene
  82.     hr = PlayMedia(szMovie, hInstance);
  83.  
  84.     // If the user interrupted playback and there was no other error,
  85.     // return S_FALSE.
  86.     if ((hr == S_OK) && g_bUserInterruptedPlayback)
  87.         hr = S_FALSE;
  88.  
  89.     // Release DirectShow interfaces
  90.     CleanupInterfaces();
  91.     CoUninitialize();
  92.  
  93.     return hr;
  94. }
  95.  
  96.  
  97. BOOL CreateHiddenWindow( HINSTANCE hInstance, TCHAR *szFile )
  98. {
  99.     TCHAR szTitle[MAX_PATH];
  100.  
  101.     // Set up and register window class
  102.     WNDCLASS wc = {0};
  103.     wc.lpfnWndProc = (WNDPROC) WindowProc;
  104.     wc.hInstance = hInstance;
  105.     wc.lpszClassName = CUTSCENE_NAME;
  106.     if (!RegisterClass(&wc))
  107.         return FALSE;
  108.  
  109.     wsprintf(szTitle, TEXT("%s: %s"), CUTSCENE_NAME, szFile);
  110.  
  111.     // Create a window of zero size that will serve as the sink for
  112.     // keyboard input.  If this media file has a video component, then
  113.     // a second ActiveMovie window will be displayed in which the video
  114.     // will be rendered.  Setting keyboard focus on this application window
  115.     // will allow the user to move the video window around the screen, make
  116.     // it full screen, resize, center, etc. independent of the application
  117.     // window.  If the media file has only an audio component, then this will
  118.     // be the only window created.
  119.     g_hwndMain = CreateWindowEx(
  120.         0, CUTSCENE_NAME, szTitle,
  121.         0,            // not visible
  122.         0, 0, 0, 0,
  123.         NULL, NULL, hInstance, NULL );
  124.  
  125.     return (g_hwndMain != NULL);
  126. }
  127.  
  128.  
  129. LONG WINAPI WindowProc( HWND hWnd, UINT message,
  130.                            WPARAM wParam, LPARAM lParam )
  131. {
  132.     switch( message )
  133.     {
  134.         // Monitor keystrokes for manipulating video window
  135.         // and program options
  136.         case WM_KEYDOWN:
  137.             switch( wParam )
  138.             {
  139.                 case VK_ESCAPE:
  140.                 case VK_SPACE:
  141.                 case VK_RETURN:
  142.                     g_bUserInterruptedPlayback = TRUE;
  143.                     CloseApp();
  144.                     break;
  145.             }
  146.             break;
  147.  
  148.         case WM_DESTROY:
  149.             PostQuitMessage(0);
  150.             return 0;
  151.     }
  152.  
  153.     return (LONG) DefWindowProc(hWnd, message, wParam, lParam);
  154. }
  155.  
  156.  
  157.  
  158. HRESULT GetInterfaces(void)
  159. {
  160.     HRESULT hr = S_OK;
  161.  
  162.     // Instantiate filter graph interface
  163.     JIF(CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC, 
  164.                          IID_IGraphBuilder, (void **)&pGB));
  165.  
  166.     // Get interfaces to control playback & screensize
  167.     JIF(pGB->QueryInterface(IID_IMediaControl,  (void **)&pMC));
  168.     JIF(pGB->QueryInterface(IID_IVideoWindow,   (void **)&pVW));
  169.  
  170.     // Get interface to allow the app to wait for completion of playback
  171.     JIF(pGB->QueryInterface(IID_IMediaEventEx,  (void **)&pME));
  172.  
  173.     return S_OK;
  174.  
  175.     // In case of failure, the helper macro jumps here
  176. CLEANUP:
  177.     CleanupInterfaces();
  178.     return(hr);
  179. }
  180.  
  181.  
  182. void CleanupInterfaces(void)
  183. {
  184.     // Release the DirectShow interfaces
  185.     RELEASE(pGB);
  186.     RELEASE(pMC);
  187.     RELEASE(pVW);
  188.     RELEASE(pME);
  189.  
  190.     DestroyWindow(g_hwndMain);
  191. }
  192.  
  193.  
  194. void CloseApp()
  195. {
  196.     // Stop playback and exit
  197.     pMC->Stop();
  198.     g_bContinue = FALSE;
  199.  
  200.     PostMessage(g_hwndMain, WM_CLOSE, 0, 0);
  201. }
  202.  
  203.  
  204.  
  205. HRESULT PlayMedia(LPTSTR lpszMovie, HINSTANCE hInstance)
  206. {
  207.     USES_CONVERSION;
  208.  
  209.     HRESULT hr = S_OK;
  210.     WCHAR wFileName[MAX_PATH];
  211.     BOOL bSleep=TRUE;
  212.  
  213.     wcscpy(wFileName, T2W(lpszMovie));
  214.  
  215.     // Allow DirectShow to create the FilterGraph for this media file
  216.     hr = pGB->RenderFile(wFileName, NULL);
  217.     if (FAILED(hr)) {
  218.         Msg(TEXT("Failed(0x%08lx) in RenderFile(%s)!\r\n"), hr, lpszMovie);
  219.         return hr;
  220.     }
  221.  
  222.     // Set the message drain of the video window to point to our hidden
  223.     // application window.  This allows keyboard input to be transferred
  224.     // to our main window for processing.
  225.     //
  226.     // If this is an audio-only or MIDI file, then put_MessageDrain will fail.
  227.     //
  228.     hr = pVW->put_MessageDrain((OAHWND) g_hwndMain);
  229.     if (FAILED(hr))
  230.     {
  231.         Msg(TEXT("Failed(0x%08lx) to set message drain for %s.\r\n\r\n")
  232.             TEXT("This sample is designed to play videos, but the file selected ")
  233.             TEXT("has no video component."), hr, lpszMovie);
  234.         return hr;
  235.     }
  236.  
  237.     // Set fullscreen
  238.     hr = SetFullscreen();
  239.     if (FAILED(hr)) {
  240.         Msg(TEXT("Failed(%08lx) to set fullscreen!\r\n"), hr);
  241.         return hr;
  242.     }
  243.  
  244.     // Display first frame of the movie
  245.     hr = pMC->Pause();
  246.     if (FAILED(hr)) {
  247.         Msg(TEXT("Failed(%08lx) in Pause()!\r\n"), hr);
  248.         return hr;
  249.     }
  250.  
  251.     // Start playback
  252.     hr = pMC->Run();
  253.     if (FAILED(hr)) {
  254.         Msg(TEXT("Failed(%08lx) in Run()!\r\n"), hr);
  255.         return hr;
  256.     }
  257.  
  258.     // Update state variables
  259.     g_bContinue = TRUE;
  260.  
  261.     // Enter a loop of checking for events and sampling keyboard i6nput
  262.     while (g_bContinue)
  263.     {
  264.         MSG msg;
  265.         long lEventCode, lParam1, lParam2;
  266.  
  267.         // Reset sleep flag
  268.         bSleep = TRUE;
  269.  
  270.         // Has there been a media event?  Look for end of stream condition.
  271.         if(E_ABORT != pME->GetEvent(&lEventCode, (LONG_PTR *) &lParam1, 
  272.                                     (LONG_PTR *) &lParam2, 0))
  273.         {
  274.             // Free the media event resources.
  275.             hr = pME->FreeEventParams(lEventCode, lParam1, lParam2);
  276.             if (FAILED(hr))
  277.             {
  278.                 Msg(TEXT("Failed(%08lx) to free event params (%s)!\r\n"),
  279.                     hr, lpszMovie);
  280.             }
  281.  
  282.             // Is this the end of the movie?
  283.             if (lEventCode == EC_COMPLETE)
  284.             {
  285.                 g_bContinue = FALSE;
  286.                 bSleep = FALSE;
  287.             }
  288.         }
  289.  
  290.         // Give system threads time to run (and don't sample user input madly)
  291.         if (bSleep)
  292.             Sleep(KEYBOARD_SAMPLE_FREQ);
  293.  
  294.         // Check and process window messages (like our keystrokes)
  295.         while (PeekMessage (&msg, g_hwndMain, 0, 0, PM_REMOVE))
  296.         {
  297.             TranslateMessage(&msg);
  298.             DispatchMessage(&msg);
  299.         }
  300.     }
  301.  
  302.     return hr;
  303. }
  304.  
  305.  
  306. HRESULT SetFullscreen(void)
  307. {
  308.     HRESULT hr=S_OK;
  309.     LONG lMode;
  310.     static HWND hDrain=0;
  311.  
  312.     if (!pVW)
  313.         return S_FALSE;
  314.  
  315.     // Read current state
  316.     LIF(pVW->get_FullScreenMode(&lMode));
  317.  
  318.     if (lMode == 0)  /* OAFALSE */
  319.     {
  320.         // Save current message drain
  321.         LIF(pVW->get_MessageDrain((OAHWND *) &hDrain));
  322.  
  323.         // Set message drain to application main window
  324.         LIF(pVW->put_MessageDrain((OAHWND) g_hwndMain));
  325.  
  326.         // Switch to full-screen mode
  327.         lMode = -1;  /* OATRUE */
  328.         LIF(pVW->put_FullScreenMode(lMode));
  329.     }
  330.  
  331.     return hr;
  332. }
  333.  
  334.  
  335. void Msg(TCHAR *szFormat, ...)
  336. {
  337.     TCHAR szBuffer[512];  // Large buffer for very long filenames (like with HTTP)
  338.  
  339.     va_list pArgs;
  340.     va_start(pArgs, szFormat);
  341.     _vstprintf(szBuffer, szFormat, pArgs);
  342.     va_end(pArgs);
  343.  
  344.     // This sample uses a simple message box to convey warning and error
  345.     // messages.   You may want to display a debug string or suppress messages
  346.     // altogether, depending on your application.
  347.     MessageBox(NULL, szBuffer, TEXT("PlayCutscene Error"), MB_OK);
  348. }
  349.  
  350.  
  351.